﻿using Abp.Application.Services.Dto;
using Abp.Auditing;
using Abp.Authorization;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.RealTime;
using Abp.Runtime.Security;
using Abp.Runtime.Session;
using Microsoft.EntityFrameworkCore;
using Mt.Site.Application.Common.Dto;
using Mt.Site.Core.Base.Authorization;
using Mt.Site.Core.Base.Authorization.Level;
using Mt.Site.Core.Base.Authorization.Users;
using Mt.Site.Core.Editions;
using Mt.Site.Core.Navigations.Modules;
using Mt.Site.Core.Navigations.Route;
using Mt.Site.Core.Url;
using Mt.Site.Core.Web;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Mt.Site.Application.Common
{
    [AbpAuthorize]
    public class CommonLookupAppService : MtSiteAppServiceBase, ICommonLookupAppService
    {
        private readonly EditionManager _editionManager;
        private readonly IUrlGetter _urlGetter;
        private readonly ITenancyNameCache _tenancyNameCache;
        private readonly IModuleManager _moduleManager;
        private readonly IRouteStore _routeStore;
        private readonly IWebUrlService _webUrlService;
        private readonly IOnlineClientManager _onlineClientManager;
        private readonly IPermissionManager _permissionManager;

        public CommonLookupAppService(
            EditionManager editionManager,
            IUrlGetter urlGetter,
            ITenancyNameCache tenancyNameCache,
            IWebUrlService webUrlService,
            IModuleManager moduleManager,
            IRouteStore routeStore,
            IOnlineClientManager onlineClientManager,
            IPermissionManager permissionManager)
        {
            _onlineClientManager = onlineClientManager;
            _editionManager = editionManager;
            _urlGetter = urlGetter;
            _tenancyNameCache = tenancyNameCache;
            _webUrlService = webUrlService;
            _moduleManager = moduleManager;
            _routeStore = routeStore;
            _permissionManager = permissionManager;
        }

        public async Task<ListResultDto<ComboboxItemDto>> GetEditionsForCombobox()
        {
            var editions = await _editionManager.Editions.ToListAsync();
            return new ListResultDto<ComboboxItemDto>(
                editions.Select(e => new ComboboxItemDto(e.Id.ToString(), e.DisplayName)).ToList()
                );
        }

        public async Task<PagedResultDto<NameValueDto>> FindUsers(FindUsersInput input)
        {
            if (AbpSession.TenantId != null)
            {
                //Prevent tenants to get other tenant's users.
                input.TenantId = AbpSession.TenantId;
            }

            var user = await GetCurrentUserAsync();
            var systemWeight = LevelEnum.System.RawValue();
            using (CurrentUnitOfWork.SetTenantId(input.TenantId))
            {
                var query = UserManager.Users
                    .Where(u => u.UserName != User.SystemUserName)
                    .WhereIf( 
                        user.AdministratorWeight < systemWeight,
                        u => u.AdministratorWeight < systemWeight)
                    .WhereIf(
                        !input.Filter.IsNullOrWhiteSpace(),
                        u =>
                            u.Name.Contains(input.Filter) ||
                            u.Surname.Contains(input.Filter) ||
                            u.UserName.Contains(input.Filter) ||
                            u.EmailAddress.Contains(input.Filter) 
                    ).WhereIf(input.ExcludeCurrentUser, u => u.Id != AbpSession.GetUserId()); ;

                var userCount = await query.CountAsync();
                
                var users = await query
                    .OrderByDescending(u => u.Order)
                    .ThenBy(u => u.Name)
                    .PageBy(input)
                    .ToListAsync();

                //return new PagedResultDto<NameValueDto>(
                //    userCount,
                //    users.Select(u =>
                //        new NameValueDto(
                //            u.FullName + " (" + u.EmailAddress + ")",
                //            u.Id.ToString()
                //            )
                //        ).ToList()
                //    );
                return new PagedResultDto<NameValueDto>(
                    userCount,
                    users.Select(u =>
                        new NameValueDto(
                            u.Name + " (" + u.Surname + ")",
                            u.Id.ToString()
                            )
                        ).ToList()
                    );
            }
        }

        public async Task<List<NameValueDto<long>>> FindUsers2()
        {
            //var user = await GetCurrentUserAsync();
            var systemWeight = LevelEnum.System.RawValue();
            using (CurrentUnitOfWork.SetTenantId(AbpSession.TenantId.Value))
            {
                var query = UserManager.Users
                    .Where(u => u.AdministratorWeight < systemWeight);

                var userCount = await query.CountAsync();

                var users = await query
                    .OrderByDescending(u => u.Order)
                    .ThenBy(u => u.Name)
                    //.PageBy(input)
                    .ToListAsync();

                return users.Select(u =>
                        new NameValueDto<long>(
                            u.Name + " (" + u.Surname + ")",
                            u.Id
                            )
                        ).ToList();
            }
        }

        public GetDefaultEditionNameOutput GetDefaultEditionName()
        {
            return new GetDefaultEditionNameOutput
            {
                Name = EditionManager.DefaultEditionName
            };
        }

        [DisableAuditing]
        public GetEtcFromBackendHeaderOutput GetEtcFromBackendHeader()
        {
            string frontendUrl;
            using (_tenancyNameCache.Use(AbpSession.TenantId, AbpSession.CultureName()))
            {
                var host = _webUrlService.GetAuthorityStr(_tenancyNameCache.TenancyName, _tenancyNameCache.CultureName, true);
                frontendUrl = host + _urlGetter.GetUrl("index", "home", 0);
            }
            var userCount = _onlineClientManager.GetAllClients().Select(c => c.UserId).Distinct().Count();

            return new GetEtcFromBackendHeaderOutput
            {
                FrontendHomeUrl = frontendUrl,
                OnlineUserCount = userCount
            };
        }

        public async Task<string> GetSpecialIds()
        {
            var str = await _moduleManager.GetConfigFileContentAsync();
            if (str.IsNullOrWhiteSpace())
            {
                return "";
            }
            str = Regex.Replace(str, @"/\*(.|[\r\n])*?\*/", "");  //去除文件中注释部分的内容
            return str;
        }

        public async Task<MenuPathOut> GetMenuRouteInfo(MenuKindInput input)
        {
            var str = await _routeStore.GetMenuRouteInfo(input.kind);
            return new MenuPathOut()
            {
                MenuRoute = str
            };
        }

        public async Task<string> GetRouterUrlAsync(Guid releateId)
        {
            var url = await _routeStore.GetRouteStrFromDbAsync(releateId, AbpSession.GetTenantId());
            url = url == null ? "" : url;
            return url;
        }

        public Dictionary<string, bool> GetPermissionDatas(GetPermissionsInput input){
            var permissions = _permissionManager.GetCustomMenuPermissions(input.ModuleName);
            var list = new Dictionary<string, bool>();
            var userId = AbpSession.GetUserId();
            foreach (var p in permissions)
            {
                list.Add(p.Name, PermissionChecker.IsGranted(userId, p, input.MenuId));
            }

            return list;
        }

        public string GetEncryptStr(GetStringCipherInput input)
        {
            var helper = new SimpleStringCipher
            {
                InitVectorBytes = Encoding.ASCII.GetBytes(input.InitVectorString)
            };
            return helper.Encrypt(input.Text, input.key);
        }

        public string GetDecryptStr(GetStringCipherInput input)
        {
            var helper = new SimpleStringCipher
            {
                InitVectorBytes = Encoding.ASCII.GetBytes(input.InitVectorString)
            };
            return helper.Decrypt(input.Text, input.key);
        }
    }
}